package org.seven.jrdp.commons.util;

import java.lang.reflect.Type;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.seven.jrdp.commons.constant.GlobalContants;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.reflect.TypeToken;

public abstract class JsonUtils {
	private static Gson gson = null;
	static {
		GsonBuilder gsonBuilder = new GsonBuilder();
		gsonBuilder.registerTypeAdapter(Date.class, new DateTypeAdapter());
		gsonBuilder.registerTypeAdapter(java.sql.Date.class, new SqlDateTypeAdapter());
		gsonBuilder.registerTypeAdapter(Timestamp.class, new TimestampTypeAdapter());
		gson = gsonBuilder.create();
	}

	public static Gson getGson() {
		return gson;
	}

	public static String getJson(Object value) {
		return gson.toJson(value);
	}

	public static <T> T getValue(String json, Class<T> clazz) {
		return gson.fromJson(json, clazz);
	}

	public static <T> List<T> getList(String json, Class<T> clazz) {
		List<JsonObject> objects = gson.fromJson(json, new TypeToken<List<JsonObject>>() {
		}.getType());
		List<T> list = new ArrayList<T>();
		for (JsonObject object : objects) {
			list.add(gson.fromJson(object, clazz));
		}
		return list;
	}

	public static List<Map<String, Object>> getList(String json) {
		List<JsonObject> objects = gson.fromJson(json, new TypeToken<List<JsonObject>>() {
		}.getType());
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		for (JsonObject object : objects) {
			list.add(getMap(object.toString()));
		}
		return list;
	}

	public static Map<String, Object> getMap(String json) {
		return gson.fromJson(json, new TypeToken<Map<String, Object>>() {
		}.getType());
	}
}

class DateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
	public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
		String json;
		if (DateTimeUtils.isTime(src)) {
			json = DateFormatUtils.format(src.getTime(), GlobalContants.PATTERN_DATETIME);
		} else {
			json = DateFormatUtils.format(src.getTime(), GlobalContants.PATTERN_DATE);
		}
		return new JsonPrimitive(json);
	}

	public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
		try {
			Date date = DateUtils.parseDate(json.getAsString(), GlobalContants.PATTERN_DATETIME, GlobalContants.PATTERN_DATE);
			return date;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}

class SqlDateTypeAdapter implements JsonSerializer<java.sql.Date>, JsonDeserializer<java.sql.Date> {
	public JsonElement serialize(java.sql.Date src, Type typeOfSrc, JsonSerializationContext context) {
		String json;
		if (DateTimeUtils.isTime(src)) {
			json = DateFormatUtils.format(src.getTime(), GlobalContants.PATTERN_DATETIME);
		} else {
			json = DateFormatUtils.format(src.getTime(), GlobalContants.PATTERN_DATE);
		}
		return new JsonPrimitive(json);
	}

	public java.sql.Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
		try {
			Date date = DateUtils.parseDate(json.getAsString(), GlobalContants.PATTERN_DATETIME, GlobalContants.PATTERN_DATE);
			return new java.sql.Date(date.getTime());
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}

class TimestampTypeAdapter implements JsonSerializer<Timestamp>, JsonDeserializer<Timestamp> {
	public JsonElement serialize(Timestamp src, Type typeOfSrc, JsonSerializationContext context) {
		String json = null;
		if (DateTimeUtils.isTime(src)) {
			json = DateFormatUtils.format(src.getTime(), GlobalContants.PATTERN_DATETIME);
		} else {
			json = DateFormatUtils.format(src.getTime(), GlobalContants.PATTERN_DATE);
		}
		return new JsonPrimitive(json);
	}

	public Timestamp deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
		try {
			Date date = DateUtils.parseDate(json.getAsString(), GlobalContants.PATTERN_DATETIME, GlobalContants.PATTERN_DATE);
			return new Timestamp(date.getTime());
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}